package lottery

import (
	"context"
	"encoding/json"
	"net/url"
	"regexp"
	"sale-admin/config"
	"sale-admin/config/mysql"
	"sale-admin/internal/app/grpc/client"
	"sale-admin/internal/app/grpc/protoc/system_admin"
	"sale-admin/internal/app/web/schema"
	"sale-admin/internal/app/web/service/common"
	"sale-admin/internal/dal"
	"sale-admin/internal/dao"
	"sale-admin/internal/define"
	"sale-admin/internal/models"
	"sort"
	"strconv"
	"strings"
	"time"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/helper"
	"192.168.1.75/go-pkg/logx"
	"github.com/PuerkitoBio/goquery"
	"github.com/golang-module/carbon"
	"github.com/samber/lo"
)

type LotteryService struct{}

// Visit 浏览量统计，没有登录的，只记录活动和参与信息等 (访问量统计, 在后台登录后就算一个)
func (ls LotteryService) Visit(
	merchantID string,
	ActivityID string,
	SalesID string, // 前端传的机器号
	OutTrade string, // 前端传的订单号
) (err error) {

	// 记录到活动日志表
	var info models.MaLotteryActivity
	mysql.NewDB().Model(&models.MaLotteryActivity{}).Where("id = ?", ActivityID).Take(&info)
	// 写入会员 浏览量
	err = LotteryMemberActivityLogService{}.Add(
		4,          // 浏览量
		SalesID,    // 用于查找当前注册的用户的来源
		ActivityID, // 活动ID
		"",         // 用户id
		OutTrade,   // 订单号
		"",         // 手机号
		"",
	)

	return
}

// 获取活动的统计数据
func (ls LotteryService) CountData(
	merchantID string,
	ActivityID string,
) (
	data map[string]interface{}, // 参与的地址,
	err error,
) {
	data = make(map[string]interface{})
	// 1. 定义今日开始和结束时间
	// StartTime1 := carbon.Now().ToDateString() + " 00:00:00"
	// EndTime1 := carbon.Now().ToDateString() + " 23:59:59"
	// carbon.Parse(StartTime1).ToStdTime().Unix() // 把日期格式转化为时间戳
	StartTime := carbon.Now().StartOfDay().ToStdTime().Unix()
	EndTime := carbon.Now().EndOfDay().ToStdTime().Unix()
	YesStartTime := carbon.Yesterday().StartOfDay().ToStdTime().Unix()
	YesEndTime := carbon.Yesterday().EndOfDay().ToStdTime().Unix()
	db := mysql.NewDB()
	{
		// 1 今日、昨日新增会员数据（单个）
		var memberCount int64
		var yesMemberCount int64
		tx := db.Model(&models.MaLotteryMember{})

		tx.Where("activity_id = ?", ActivityID)
		// 统计今日的数据
		tx.Where("created_at between ? and ?", StartTime, EndTime)
		tx.Count(&memberCount)
		// 获取今日新增会员个数
		data["today_add_member"] = memberCount //1
		// 统计昨日的数据
		tx1 := db.Model(&models.MaLotteryMember{})
		tx1.Where("created_at between ? and ?", YesStartTime, YesEndTime)
		tx1.Count(&yesMemberCount)
		// 获取昨日新增会员个数
		data["yes_today_add_member"] = yesMemberCount //1.1

		// 2 累计会员数（单个）
		var totalAddMember int64
		tx2 := db.Model(&models.MaLotteryMember{})
		tx2.Where("activity_id = ?", ActivityID)
		tx2.Count(&totalAddMember)
		data["total_add_member"] = totalAddMember
	}
	{
		// 3 参与抽奖人数（单个） --- 1.从日志里面查询，并且进行去重
		// 					  --- 2.从抽奖码里面，对用户进行去重
		var count int64
		tx := db.Model(&models.MaLotteryMemberActiveLog{})
		tx.Where("lottery_activity_id = ?", ActivityID)
		tx.Where("created_at between ? and ?", StartTime, EndTime)
		tx.Where("type = ?", 2)
		tx.Group("customer_id")
		tx.Count(&count)
		// 今日
		data["total_member_count_of_lottery"] = count

		var yescount int64
		tx1 := db.Model(&models.MaLotteryMemberActiveLog{})
		tx1.Where("lottery_activity_id = ?", ActivityID)
		tx1.Where("created_at between ? and ?", YesStartTime, YesEndTime)
		tx1.Where("type = ?", 2)
		tx1.Group("customer_id")
		tx1.Count(&yescount)

		// 昨日
		data["yes_total_member_count_of_lottery"] = yescount

	}

	{
		// 4 参与的抽奖次数（单个）,一个人可以参与多次，所以不做去重
		var count int64
		tx := db.Model(&models.MaLotteryMemberActiveLog{})
		tx.Where("lottery_activity_id = ?", ActivityID)
		tx.Where("created_at between ? and ?", StartTime, EndTime)
		tx.Where("type = ?", 2)
		tx.Count(&count)
		// 今日
		data["total_count_of_lottery"] = count

		var yes_count int64
		tx1 := db.Model(&models.MaLotteryMemberActiveLog{})
		tx1.Where("lottery_activity_id = ?", ActivityID)
		tx1.Where("created_at between ? and ?", YesStartTime, YesEndTime)
		tx1.Where("type = ?", 2)
		tx1.Count(&yes_count)
		// 昨日
		data["yes_total_count_of_lottery"] = yes_count
	}

	{
		// 5 访客数（单个）

		var count int64
		tx := db.Model(&models.MaLotteryMemberActiveLog{})
		tx.Where("lottery_activity_id = ?", ActivityID)
		tx.Where("created_at between ? and ?", StartTime, EndTime)
		tx.Where("type = ?", 3)
		tx.Count(&count)
		// 今日
		data["total_visit"] = count

		var yes_count int64
		tx1 := db.Model(&models.MaLotteryMemberActiveLog{})
		tx1.Where("lottery_activity_id = ?", ActivityID)
		tx1.Where("created_at between ? and ?", YesStartTime, YesEndTime)
		tx1.Where("type = ?", 3)
		tx1.Count(&yes_count)
		// 昨日
		data["yes_total_visit"] = yes_count
	}

	{
		// 6 浏览数（单个）

		var count int64
		tx := db.Model(&models.MaLotteryMemberActiveLog{})
		tx.Where("lottery_activity_id = ?", ActivityID)
		tx.Where("created_at between ? and ?", StartTime, EndTime)
		tx.Where("type = ?", 4)
		tx.Count(&count)
		// 今日
		data["total_view"] = count

		var yes_count int64
		tx1 := db.Model(&models.MaLotteryMemberActiveLog{})
		tx1.Where("lottery_activity_id = ?", ActivityID)
		tx1.Where("created_at between ? and ?", YesStartTime, YesEndTime)
		tx1.Where("type = ?", 4)
		tx1.Count(&yes_count)
		// 昨日
		data["yes_total_view"] = yes_count

	}

	{
		// 7 获取支付金额（单个）
		var totalPaymentAmount struct {
			PaymentAmount float32 `json:"payment_amount"`
		}
		var yesTotalPaymentAmount struct {
			PaymentAmount float32 `json:"payment_amount"`
		}
		db.Table(models.MaLotteryMemberActiveLog{}.TableName()+" as m").
			Joins("left join "+models.MaOrder{}.TableName()+" as o on o.out_trade_no = m.out_trade_no").
			Select("sum(o.payment_amount) as payment_amount").
			Where("o.order_status = 4").
			Where("m.type = 2").
			Where("m.created_at between ? and ?", StartTime, EndTime).
			Take(&totalPaymentAmount)
		data["total_payment_amount"] = totalPaymentAmount.PaymentAmount

		db.Table(models.MaLotteryMemberActiveLog{}.TableName()+" as m").
			Joins("left join "+models.MaOrder{}.TableName()+" as o on o.out_trade_no = m.out_trade_no").
			Select("sum(o.payment_amount) as payment_amount").
			Where("o.order_status = 4").
			Where("m.type = 2").
			Where("m.created_at between ? and ?", YesStartTime, YesEndTime).
			Take(&yesTotalPaymentAmount)
		data["yes_total_payment_amount"] = yesTotalPaymentAmount.PaymentAmount
	}

	{
		// 8 获取成功退款金额（单个）
		var totalPaymentAmount struct {
			PaymentAmount float32 `json:"payment_amount"`
		}
		db.Table(models.MaLotteryMemberActiveLog{}.TableName()+" as m").
			Joins("left join "+models.MaOrder{}.TableName()+" as o on o.out_trade_no = m.out_trade_no").
			Select("sum(o.payment_amount) as payment_amount").
			Where("o.order_status = 6").
			Where("m.type = 2").
			Where("m.created_at between ? and ?", YesStartTime, YesEndTime).
			Take(&totalPaymentAmount)
		data["total_refund_amount"] = totalPaymentAmount.PaymentAmount
	}

	{
		// 9 获取支付订单数（单个）
		var totalPaymentAmount struct {
			PaymentNum int `json:"payment_num"`
		}
		db.Table(models.MaLotteryMemberActiveLog{}.TableName()+" as m").
			Joins("left join "+models.MaOrder{}.TableName()+" as o on o.out_trade_no = m.out_trade_no").
			Select("count(o.out_trade_no) as payment_num").
			Where("o.order_status = 4").
			Where("m.type = 2").
			Where("m.created_at between ? and ?", StartTime, EndTime).
			Take(&totalPaymentAmount)
		data["total_pay_num"] = totalPaymentAmount.PaymentNum

		var yesTotalPaymentAmount struct {
			PaymentNum int `json:"payment_num"`
		}
		db.Table(models.MaLotteryMemberActiveLog{}.TableName()+" as m").
			Joins("left join "+models.MaOrder{}.TableName()+" as o on o.out_trade_no = m.out_trade_no").
			Select("count(o.out_trade_no) as payment_num").
			Where("o.order_status = 4").
			Where("m.type = 2").
			Where("m.created_at between ? and ?", YesStartTime, YesEndTime).
			Take(&totalPaymentAmount)
		data["total_pay_num"] = yesTotalPaymentAmount.PaymentNum

	}
	return
}

// type myVisitInfo struct {
// 	models.MaLotteryMemberActiveLog
// }

type VisitRecord struct {
	Type  int    `gorm:"column:type"`
	Date  string `json:"date" gorm:"column:date"`
	Count int64  `json:"count" gorm:"column:count"`
}

// 获取活动的一段时间的数据
func (ls LotteryService) TrendOfLottery(
	merchantID,
	ActivityID string,
	CityID string,
	startTime, endTime int64,
) (
	data map[string][]VisitRecord,
	err error,
) {
	db := mysql.NewDB()
	// 开始和结束时间
	startDate := carbon.NewCarbon().CreateFromTimestamp(startTime).ToDateString()
	endDate := carbon.NewCarbon().CreateFromTimestamp(endTime).ToDateString()
	dates := common.GetDatePeriods(startDate, endDate)
	// 查询活动信息
	var lotteryInfo models.MaLotteryActivity
	db.Model(&models.MaLotteryActivity{}).
		Where("id = ?", ActivityID).Find(&lotteryInfo)

	// 获取整体趋势，支持时间和活动ID检索
	var visitRecords = []VisitRecord{}
	// 1. 浏览量、访客量
	tx := db.Table(models.MaLotteryMemberActiveLog{}.TableName() + " as m").
		Joins("inner join " + models.MaRobot{}.TableName() + " as r on r.sales_id = m.sales_id")
	// 1、指定活动ID 当前的数据都是属于某个活动下的
	tx.Where("m.lottery_activity_id = ?", ActivityID)

	// 2、检索时间
	if startTime > 0 && endTime > 0 {
		tx.Where("m.created_at BETWEEN ? AND ?", startTime, endTime)
	}

	// 3、 检索城市ID
	if CityID != "" && lotteryInfo.AllowCitys != "" {
		// 比如配置的是10001,30003，但传了10001,20001,30003 其中只要任何一个城市ID匹配上都能单独查询到数据. 做法：依据日志表的salesid，判断筛选的城市
		tx.Where("r.areas2 in (?)", strings.Split(CityID, ",")) // 一个活动可以有多个城市。查询指定城市下的活动数据
	}

	tx.Select("m.type,m.created_date as date, count(m.id) as count")
	tx.Group("m.created_date, m.type")
	tx.Find(&visitRecords)

	datePageViewMap := make(map[string]int64)
	// datePageViewMap := make(map[string]VisitRecord)
	dateUserViewMap := make(map[string]int64)
	dateLotteryCountMap := make(map[string]int64)
	// 初始化
	for _, date := range dates {
		datePageViewMap[date] = 0
		dateUserViewMap[date] = 0
		dateLotteryCountMap[date] = 0
	}
	// 根据查询结果赋值
	for _, record := range visitRecords {
		switch record.Type {
		case 3:
			datePageViewMap[record.Date] = record.Count
		case 4:
			dateUserViewMap[record.Date] = record.Count
		case 2: //
			dateLotteryCountMap[record.Date] = record.Count
		}
	}
	retdata := make(map[string][]VisitRecord)
	for k, v := range datePageViewMap {
		retdata["page_view"] = append(retdata["page_view"], VisitRecord{
			Date:  k,
			Count: v,
		})
	}

	for k, v := range dateUserViewMap {
		retdata["user_view"] = append(retdata["user_view"], VisitRecord{
			Date:  k,
			Count: v,
		})
	}

	for k, v := range dateLotteryCountMap {
		retdata["lottery_count"] = append(retdata["lottery_count"], VisitRecord{
			Date:  k,
			Count: v,
		})
	}
	sort.Slice(retdata["page_view"], func(i, j int) bool {
		return retdata["page_view"][i].Date < retdata["page_view"][j].Date
	})
	sort.Slice(retdata["user_view"], func(i, j int) bool {
		return retdata["user_view"][i].Date < retdata["user_view"][j].Date
	})
	sort.Slice(retdata["lottery_count"], func(i, j int) bool {
		return retdata["lottery_count"][i].Date < retdata["lottery_count"][j].Date
	})
	return retdata, err
}

// 获取符合当前参与条件的活动
func (ls LotteryService) CheckLotteryActivity(
	SalesID string,
	OutTradeNo string,
) (
	urlPath string, // 参与的地址,
	err error,
) {
	// 检查当前机器的订单可以获取的订单
	if SalesID == "" && OutTradeNo == "" {
		return
	}
	db := mysql.NewDB()
	// 1. 获取机器信息
	var RobotInfo = models.MaRobot{}
	robot := db.Model(&models.MaRobot{})
	robot.Where("sales_id = ?", SalesID).Take(&RobotInfo)

	// 1. 获取订单信息
	var OrderInfo = models.MaOrder{}
	order := db.Model(&models.MaOrder{})
	var OrderCount int64
	order.Where("out_trade_no = ?", OutTradeNo).Where("order_status = ?", 4).
		Take(&OrderInfo).
		Count(&OrderCount)
	if OrderCount == 0 {
		// 订单不符合参与条件
		return
	}

	// 2. 获取正在进行中的活动
	var ActivityInfo = []models.MaLotteryActivity{}
	var now = time.Now().Unix()
	tx := db.Model(&models.MaLotteryActivity{})
	tx.Where("status = 1")                                  // 活动必须进行中
	tx.Where("start_time <= ? and end_time >= ?", now, now) // 时间必须进行中
	tx.Find(&ActivityInfo)

	if len(ActivityInfo) > 0 {
		// 如果有多个活动，依次循环
		// 如果机器符合参与条件，则返回活动地址
		for _, v := range ActivityInfo {

			// 1 判断是否需要消费金额限制多少 order_amount_required【消费金额限制 tinyint 0-不需要消费，1 需要
			OrderPaymentAmount := OrderInfo.PaymentAmount
			// 1 限制 2不限制 （默认）
			if v.OrderAmountRequired == 1 && OrderPaymentAmount < v.OrderAmount {
				// 不能参与，对比下一个活动
				continue
			}

			// 2 判断当前的机器，是否在【设定的城市中】
			if v.AllowCitys != "" {
				City := strconv.Itoa(RobotInfo.Areas2)
				if !strings.Contains(v.AllowCitys, City) {
					// 不能参与，对比下一个活动
					continue
				}
			}

			// 判断当前机器是否可参与抽奖活动
			if !(dao.ObjAssociation{}).ExistAssociation(
				context.Background(),
				dal.Q,
				define.AssociationLotteryRobot,
				v.ID,
				RobotInfo.RobotName,
			) {
				continue
			}

			// 判断当前的订单商品是否可参与抽奖
			{
				// 订单商品id
				var CountDataList []schema.OrderGoodsDetailOld
				var orderGoodsIDs []string
				json.Unmarshal([]byte(OrderInfo.CountData), &CountDataList)
				for _, data := range CountDataList {
					orderGoodsIDs = append(orderGoodsIDs, data.GoodsID)
				}
				// 活动商品id
				activityGoodsIDs, _ := (dao.ObjAssociation{}).GetAssociationID(
					context.Background(),
					dal.Q,
					define.AssociationLotteryGoods,
					v.ID, "",
				)
				if len(activityGoodsIDs) > 0 {
					if len(lo.Intersect(activityGoodsIDs, orderGoodsIDs)) <= 0 {
						continue
					}
				}
			}
			// 返回活动H5地址
			{
				var URL url.URL
				query := URL.Query()
				query.Add("activity_id", v.ID)        // 活动ID
				query.Add("out_trade_no", OutTradeNo) // 订单号
				query.Add("sales_id", SalesID)        // 机器唯一识别码
				// 根据活动类型；返回不同的H5参与界面
				if v.Type == 1 {
					// 兑换码
					// urlPath = config.Config.BaseUrl + "/h5-page/page97/index.html#/pages/lottery-activity/guide?activity_id=" + v.ID + "&out_trade_no=" + OutTradeNo + "&sales_id=" + SalesID
					urlPath = config.Config.BaseUrl + "/h5-page/page97/index.html#/pages/lottery-activity/guide?" + query.Encode()
				} else if v.Type == 2 {
					// 扭蛋机
					urlPath = config.Config.BaseUrl + "/h5-page/page97/index.html#/pages/raffle-activity/guide?" + query.Encode()
				}
				return
			}
		}
	}
	return
}

// List 锦鲤活动列表
func (ls LotteryService) List(ctx context.Context, merchantID string,
	Page, Limit int,
	Name string,
	OrderAmountRequired int,
	OrderAmount float64,
	StartTime,
	EndTime string,
	Status int,
	ActivityStatus int,
	Type int,
	Desc string,
	WinOdds float64,
	TotalWinTimes,
	DailyWinTimes,
	TotalLotteryTimes,
	DaliyLotteryTimes int,
	WechatImg,
	ServicePhone string,
	AllowCitys string,
) (
	list []models.MaLotteryActivity,
	count int64,
	err error,
) {
	db := mysql.NewDB()
	tx := db.Model(&models.MaLotteryActivity{})
	// 有哪些检索的字段？

	// 检索允许参与城市ID
	if AllowCitys != "" {
		tx.Where("allow_citys like ?", "%"+AllowCitys+"%")
	}

	// 1. 检索活动名称
	if Name != "" {
		tx.Where("name like ?", "%"+Name+"%")
	}
	// 2. 检索活动状态
	if Status != 0 {
		tx.Where("status = ?", Status)
	}

	// 2. 检索活动状态（时间维度）
	if ActivityStatus != 0 {
		// tx.Where("status = ?", Status)
		// 时间检索区分 ActivityStatus, //  3已结束
		if ActivityStatus == 1 {
			// 1未开始
			tx.Where("start_time > ?", time.Now().Unix())
		}
		if ActivityStatus == 2 {
			// 2进行中
			tx.Where("start_time < ? and end_time > ?", time.Now().Unix(), time.Now().Unix())
		}
		if ActivityStatus == 3 {
			// 3已结束
			tx.Where("end_time < ?", time.Now().Unix())
		}
	}

	// 正常的状态
	tx.Where("deleted_at = 0")

	// 3. 检索开始和结束时间
	if StartTime != "" && EndTime != "" {
		tx.Where("start_time > ? and end_time < ?", StartTime, EndTime)
	}

	tx.Count(&count)
	// 赋空值
	list = []models.MaLotteryActivity{}
	// helper.Gorm{}.Paginate(tx, int(Page), int(Limit)).Find(&list)
	helper.Gorm{}.Paginate(tx, int(Page), int(Limit)).
		Select("*, case when (start_time > ?) then 1 when (start_time < ? and end_time > ?) then 2 when end_time < ? then 3 end as activity_status", time.Now().Unix(), time.Now().Unix(), time.Now().Unix(), time.Now().Unix()).
		Order("find_in_set(activity_status,'2,1,3')").
		Find(&list)

	now := time.Now().Unix()
	for k, v := range list {
		// 查询当前活动下的机器ID
		robotIDs, _ := dao.ObjAssociation{}.GetAssociationID(ctx, dal.Q, define.AssociationLotteryRobot, v.ID, "")
		if len(robotIDs) > 0 {
			list[k].AllowRobots = strings.Join(robotIDs, ",")
		}
		// 查询允许机器所在的位置
		var robotSlice = []models.MaRobot{}
		db.Model(&models.MaRobot{}).
			Where("robot_name in (?)", robotIDs).
			Find(&robotSlice)
		var stringLocation string
		for _, v := range robotSlice {
			stringLocation += strconv.Itoa(v.Areas3) + ","
		}
		stringLocation = strings.TrimRight(stringLocation, ",")
		list[k].AllowLocationID += stringLocation

		if now < int64(v.StartTime) {
			list[k].ActivityStatus = 1 // 未开始
		}
		if now < int64(v.EndTime) && now > int64(v.StartTime) {
			list[k].ActivityStatus = 2 // 进行中
		}
		if now > int64(v.EndTime) {
			list[k].ActivityStatus = 3 // 已结束
		}
	}

	sort.Slice(list, func(i, j int) bool {
		return list[i].ActivityStatus < list[j].ActivityStatus
	})

	return
}

// List
func (ls LotteryService) All(ctx context.Context, merchantID string,
	Page, Limit int,
	Name string,
	OrderAmountRequired int,
	OrderAmount float64,
	StartTime,
	EndTime string,
	Status int,
	Type int,
	Desc string,
	WinOdds float64,
	TotalWinTimes,
	DailyWinTimes,
	TotalLotteryTimes,
	DaliyLotteryTimes int,
	WechatImg,
	ServicePhone string,
	AllowCitys string,
) (
	list []All,
	count int64,
	err error,
) {
	db := mysql.NewDB()
	tx := db.Model(&models.MaLotteryActivity{})
	// 有哪些检索的字段？

	// 检索允许参与城市ID
	if AllowCitys != "" {
		tx.Where("allow_citys = ? and deleted_at = 0", AllowCitys)
	}

	// 1. 检索活动名称
	if Name != "" {
		tx.Where("name like ? and deleted_at = 0", "%"+Name+"%")
	}
	// 2. 检索活动状态
	if Status != 0 {
		tx.Where("status = ? and deleted_at = 0", Status)
	}

	// 3. 检索开始和结束时间
	if StartTime != "" && EndTime != "" {
		tx.Where("start_time > ? and end_time < ?", StartTime, EndTime)
	}
	tx.Count(&count)
	// 赋空值
	list = []All{}
	helper.Gorm{}.Paginate(tx, int(Page), int(Limit)).Select("id,name").Find(&list)
	return
}

// 只返回name和id字段
type All struct {
	Name string `json:"name"`
	ID   string `json:"id"`
}

type LotteryActivityDetail struct {
	ID                  string  `json:"id"`
	Name                string  `json:"name"`
	OrderAmountRequired int     `json:"order_amount_required"`
	OrderAmount         float64 `json:"order_amount"`
	StartTime           int     `json:"start_time"`
	EndTime             int     `json:"end_time"`
	Status              int     `json:"status"`
	Type                int     `json:"type"`
	Desc                string  `json:"desc"`
	TotalWinTimes       int     `json:"total_win_times"`
	DailyWinTimes       int     `json:"daily_win_times"`
	TotalLotteryTimes   int     `json:"total_lottery_times"`
	DaliyLotteryTimes   int     `json:"daliy_lottery_times"`
	WechatImg           string  `json:"wechat_img"`
	ServicePhone        string  `json:"service_phone"`
	AllowCitys          string  `json:"allow_citys"`
	ActivityStatus      int     `gorm:"-" json:"activity_status"`
	// 迁移到ma_lottery_activity表
	RedemptionStartTime int    `json:"redemption_start_time"`
	RedemptionEndTime   int    `json:"redemption_end_time"`
	RedemptionStartWeek string `json:"redemption_start_week"`

	PrizeData       []schema.LotteryPrizeRuleData `gorm:"-" json:"prize_data"`
	AllowGoods      []schema.LotteryGoods         `gorm:"-" json:"allow_goods"`
	AllowRobots     string                        `gorm:"-" json:"allow_robots"`
	AllowLocationID string                        `gorm:"-" json:"allow_location_id"`
	ThemesColor     string                        `json:"themes_color"`
	ThemesImage     string                        `json:"themes_image"`
}

// Detail [单个活动详情]
func (ls LotteryService) Detail(merchantID, ID string) (
	info LotteryActivityDetail,
	err error,
) {
	db := mysql.NewDB()
	db.Model(&models.MaLotteryActivity{}).
		Where("id = ? and deleted_at = 0", ID).
		Take(&info)
		// 如果活动有效，则获取奖项设置及奖品设置
	if info.ID != "" {
		// 3.获取单个或多个奖项规则【例如：一等奖、二等奖、谢谢参与等待】
		var PrizeRule = []models.MaLotteryPrizeRule{}
		db.Model(&models.MaLotteryPrizeRule{}).
			Where("lottery_activity_id = ? and deleted_at = 0", info.ID).
			Find(&PrizeRule)
		// ActivityStatus
		now := time.Now().Unix()
		if now < int64(info.StartTime) {
			info.ActivityStatus = 1
		}
		if now < int64(info.EndTime) && now > int64(info.StartTime) {
			info.ActivityStatus = 2
		}
		if now > int64(info.EndTime) {
			info.ActivityStatus = 3
		}

		// 查询允许机器所在的位置
		allowRobotIDs, _ := dao.ObjAssociation{}.GetAssociationID(context.Background(), dal.Q, define.AssociationLotteryRobot, info.ID, "")
		// 查询允许机器所在的位置
		var robotSlice = []models.MaRobot{}
		db.Model(&models.MaRobot{}).
			Where("robot_name in (?)", allowRobotIDs).
			Find(&robotSlice)
		var stringLocation string
		for _, v := range robotSlice {
			stringLocation += strconv.Itoa(v.Areas3) + ","
		}
		stringLocation = strings.TrimRight(stringLocation, ",")
		info.AllowLocationID += stringLocation

		// 循环奖项
		for _, v := range PrizeRule {
			var item schema.LotteryPrizeRuleData
			item.ID = v.ID
			item.Name = v.Name
			item.RuleType = v.RuleType
			item.WinOdds = v.WinOdds
			item.Total = v.Total

			// 获取该奖项的已经中奖数,从抽奖订单中(ma_lottery_order)，其中状态未出货成功
			var prizeRuleIDCount int64
			db.Model(&models.MaLotteryOrder{}).
				Where("activity_id = ?", info.ID).
				Where("prize_rule_id = ?", v.ID). // 查询中奖订单表，当前奖项的中奖订单总数
				Count(&prizeRuleIDCount)
			if prizeRuleIDCount >= 0 {
				item.Win = prizeRuleIDCount
			}
			// 获取该奖项的剩余奖数
			if item.Win > 0 {
				// 剩余奖项数量
				item.Last = item.Total - item.Win
			} else {
				item.Last = item.Total
			}

			// 获取【当前奖项】下的所有奖品
			prizeGoodsIDs, _ := dao.ObjAssociation{}.GetAssociationID(context.Background(), dal.Q, define.AssociationLotteryPrize, v.ID, "")
			if len(prizeGoodsIDs) > 0 {
				for _, goodsID := range prizeGoodsIDs {
					var goodsInfo models.MaGoodsInfo
					db.Model(&models.MaGoodsInfo{}).
						Where("goods_id = ?", goodsID).
						Find(&goodsInfo)
					// 查询商品信息，用于前端回显
					item.PrizeGoodsIDSlice = append(item.PrizeGoodsIDSlice, schema.LotteryGoods{
						GoodsID:    goodsInfo.GoodsID,
						GoodsName:  goodsInfo.GoodsName1,
						GoodsImage: goodsInfo.GoodsImage,
					})
				}
			}
			info.PrizeData = append(info.PrizeData, item)
		}

		// 获取允许参与抽奖的商品
		goodsIDs, _ := dao.ObjAssociation{}.GetAssociationID(context.Background(), dal.Q, define.AssociationLotteryGoods, info.ID, "")
		info.AllowGoods = []schema.LotteryGoods{}
		if len(goodsIDs) > 0 {
			for _, goodsID := range goodsIDs {
				var goodsInfo models.MaGoodsInfo
				db.Model(&models.MaGoodsInfo{}).
					Where("goods_id = ?", goodsID).
					Find(&goodsInfo)
				info.AllowGoods = append(info.AllowGoods, schema.LotteryGoods{
					GoodsID:    goodsInfo.GoodsID,
					GoodsName:  goodsInfo.GoodsName1,
					GoodsImage: goodsInfo.GoodsImage,
				})
			}
		}
		// 获取允许参与的机器
		if len(allowRobotIDs) > 0 {
			info.AllowRobots = strings.Join(allowRobotIDs, ",")
		}
	}
	return
}

type PrizeListStruct struct {
	// 奖品类型
	PrizeName string `json:"prize_name"`
	// 奖品ID
	GoodsID string `json:"goods_id"`
	// 奖品名称
	GoodsName string `json:"goods_name"`
	// 奖品图片地址
	GoodsImage string `json:"goods_image"`
}

// PrizeList [获取活动的奖品] -- 传入活动ID
func (ls LotteryService) PrizeList(merchantID, ActivityID string) (
	mySlice []PrizeListStruct,
	err error,
) {
	db := mysql.NewDB()
	// 1.先获取当前活动的所有奖项。
	var prize_rule = []models.MaLotteryPrizeRule{}
	db.Model(&models.MaLotteryPrizeRule{}).
		Where("lottery_activity_id = ?", ActivityID).
		Find(&prize_rule)
	// 2.获取奖项下的奖品
	// var mySlice = []PrizeListStruct{}
	if len(prize_rule) > 0 {
		// 定义返回的数据
		for _, v := range prize_rule {
			prizeGoodsIDs, _ := dao.ObjAssociation{}.GetAssociationID(context.Background(), dal.Q, define.AssociationLotteryPrize, v.ID, "")
			// 3.使用切片方式返回所有奖品
			for _, goodsID := range prizeGoodsIDs {
				// 查询商品的信息
				var goodsInfo models.MaGoodsInfo
				db.Model(&models.MaGoodsInfo{}).
					Where("goods_id = ?", goodsID).
					Where("goods_type = 7").
					Find(&goodsInfo)
				if goodsInfo.GoodsName1 != "" {
					var item PrizeListStruct
					item.PrizeName = v.Name
					item.GoodsID = goodsInfo.GoodsID
					item.GoodsName = goodsInfo.GoodsName1
					item.GoodsImage = goodsInfo.GoodsImage
					mySlice = append(mySlice, item)
				}
			}
		}
	}
	return mySlice, nil
}

func (ls LotteryService) DetailOnly(merchantID, ID string) (info models.MaLotteryActivity, err error) {
	db := mysql.NewDB()
	db.Model(&models.MaLotteryActivity{}).
		Where("id = ? and deleted_at = 0", ID).
		Take(&info)
	return
}

// Del
func (ls LotteryService) Del(merchantID, ID string) (err error) {

	db := mysql.NewDB()
	db.Model(&models.MaLotteryActivity{}).
		// Where("start_time > ?", time.Now().Unix()). // 当前时间 < 活动开始时间
		Where("id = ? and deleted_at = 0", ID).Delete(&models.MaLotteryActivity{})
	return
}

// SetStatus 修改活动状态：1启动 2禁用
func (ls LotteryService) SetStatus(merchantID, ID string, Status int) (err error) {

	db := mysql.NewDB()
	var updateData = make(map[string]interface{})
	updateData["status"] = Status
	// 执行修改
	db.Model(&models.MaLotteryActivity{}).
		Where("id = ? and deleted_at = 0", ID).
		UpdateColumns(&updateData)
	return
}

// Add 添加抽奖活动
func (ls LotteryService) Add(
	merchantID,
	ID string,
	Name string,
	OrderAmountRequired int,
	OrderAmount float64,
	StartTime, EndTime int,
	Status int,
	Type int,
	Desc string,
	TotalWinTimes,
	DailyWinTimes,
	TotalLotteryTimes,
	DaliyLotteryTimes int,
	WechatImg,
	ServicePhone string,
	AllowCitys string,
	AllowRobots string,
	AllowGoods string,
	ThemesColor string,
	ThemesImage string,
	RedemptionStartTime int,
	RedemptionEndTime int,
	RedemptionStartWeek string,
	PrizeData []schema.LotteryPrizeRuleData, // 奖项设置相关数据
) (err error) {

	db := mysql.NewDB()
	if ID == "" {
		var InsertData models.MaLotteryActivity
		InsertData.Name = Name
		InsertData.OrderAmountRequired = OrderAmountRequired
		InsertData.OrderAmount = OrderAmount
		InsertData.StartTime = StartTime
		InsertData.EndTime = EndTime
		InsertData.Status = Status
		InsertData.Type = Type
		InsertData.Desc = HandlerGoodsDetail(Desc)

		InsertData.TotalWinTimes = TotalWinTimes
		InsertData.DailyWinTimes = DailyWinTimes
		InsertData.TotalLotteryTimes = TotalLotteryTimes
		InsertData.DaliyLotteryTimes = DaliyLotteryTimes
		InsertData.ThemesColor = ThemesColor
		// InsertData.ThemesImage = ThemesImage

		// if (DaliyLotteryTimes != -1 && TotalLotteryTimes != -1) && DaliyLotteryTimes > TotalLotteryTimes {
		// err = errorx.New("单日总抽奖机会超过总抽奖机会", -1)
		// return
		// }
		InsertData.ServicePhone = ServicePhone
		// 1.城市ID，不传则默认为''
		if AllowCitys != "" {
			InsertData.AllowCitys = AllowCitys
		}

		// 2.图片提交时，需确认文件
		SystemAdminClient, clientErr := client.GetSystemAdminClient()
		if clientErr != nil {
			err = clientErr
			return
		}
		var req system_admin.ConfirmFileReq
		req.FileUrl = WechatImg
		res, err1 := SystemAdminClient.ConfirmFile(context.Background(), &req)
		if err1 != nil && res.Code != 0 {
			logx.Error(context.Background(), "activity confirm file error", logx.Any("res", res), logx.Any("err", err1.Error()))
			return
		}

		// 2.1 确认主题背景图
		var req1 system_admin.ConfirmFileReq
		req1.FileUrl = ThemesImage
		res1, err2 := SystemAdminClient.ConfirmFile(context.Background(), &req1)
		if err2 != nil && res1.Code != 0 {
			logx.Error(context.Background(), "activity confirm file error", logx.Any("res1", res1), logx.Any("err", err2.Error()))
			return
		}
		InsertData.ThemesImage = res1.FileUrl // 主题图片地址
		InsertData.WechatImg = res.FileUrl    // 微信客服图片地址

		InsertData.RedemptionStartTime = RedemptionStartTime
		InsertData.RedemptionEndTime = RedemptionEndTime
		InsertData.RedemptionStartWeek = RedemptionStartWeek
		// if RedemptionStartTime < StartTime {
		// 	err = errorx.New("兑换时间不能小于当前的活动开始时间", -1)
		// 	return
		// }

		// 3.添加活动奖项设置，写入奖项设置及奖品数据
		UUID, _ := helper.UUID{}.String()
		InsertData.ID = UUID
		if len(PrizeData) > 0 {
			// 允许参与的机器,最多添加500个
			if AllowRobots != "" {
				records := []*models.MaObjAssociation{}
				var AllowRobotIDs = strings.Split(AllowRobots, ",")
				for _, robotID := range AllowRobotIDs {
					records = append(records, &models.MaObjAssociation{
						AssociationType: int(define.AssociationLotteryRobot),
						ObjID:           InsertData.ID,
						AssociationID:   robotID,
					})
				}
				_, err = dao.ObjAssociation{}.Add(context.Background(), dal.Q, records, 300)
				if err != nil {
					err = errorx.New("操作失败", -1)
					return
				}
			}

			// 允许参与的商品,最多添加100个
			if AllowGoods != "" {
				records := []*models.MaObjAssociation{}
				var AllowGoodsIDs = strings.Split(AllowGoods, ",")
				for _, goodsID := range AllowGoodsIDs {
					records = append(records, &models.MaObjAssociation{
						AssociationType: int(define.AssociationLotteryGoods),
						ObjID:           InsertData.ID,
						AssociationID:   goodsID,
					})
				}
				_, err = dao.ObjAssociation{}.Add(context.Background(), dal.Q, records, 300)
				if err != nil {
					err = errorx.New("操作失败", -1)
					return
				}
			}

			// 1 奖品规则表
			var AllOdds float64
			var OnlyPrizeName = make(map[string]string)
			var ObjTypeTwo = false

			for _, val := range PrizeData {
				AllOdds += val.WinOdds
				// --- 奖项名称已经存在！---
				if OnlyPrizeName[val.Name] != "" {
					err = errorx.New("奖项名称已经存在！", -1)
					return
				} else {
					OnlyPrizeName[val.Name] = "1"
				}
				if val.RuleType == 2 {
					ObjTypeTwo = true
				}
			}
			// 1.概率加起来必须是100%
			if AllOdds != 100 {
				err = errorx.New("概率设置必须等100%", -1)
				return
			}
			if !ObjTypeTwo {
				err = errorx.New("必须设置谢谢参与的奖项", -1)
				return
			}
			for _, v := range PrizeData {

				UUID1, _ := helper.UUID{}.String()
				var prizeRule models.MaLotteryPrizeRule
				prizeRule.ID = UUID1
				prizeRule.Sort = v.Sort
				prizeRule.Name = v.Name
				prizeRule.LotteryActivityID = UUID
				prizeRule.LotteryPrizeType = v.LotteryPrizeType
				prizeRule.WinOdds = v.WinOdds

				prizeRule.Total = v.Total
				prizeRule.RuleType = v.RuleType

				// 写入关联表（存储的是奖品ID）
				if v.PrizeGoodsID != "" {
					// 解析字符串到数组
					records := []*models.MaObjAssociation{}
					var prizeGoodsIDs = strings.Split(v.PrizeGoodsID, ",")
					for _, goodsID := range prizeGoodsIDs {
						records = append(records, &models.MaObjAssociation{
							AssociationType: int(define.AssociationLotteryPrize),
							ObjID:           prizeRule.ID,
							AssociationID:   goodsID,
						})
					}
					_, err = dao.ObjAssociation{}.Add(context.Background(), dal.Q, records, 300)
					if err != nil {
						err = errorx.New("操作失败", -1)
						return
					}
				}
				// 写入奖品规则表
				err = db.Model(&models.MaLotteryPrizeRule{}).Create(&prizeRule).Error
				if err != nil {
					err = errorx.New("操作失败", -1)
					return
				}

			}

		}
		// 执行写入
		err = db.Model(&models.MaLotteryActivity{}).Create(&InsertData).Error
		if err != nil {
			err = errorx.New("新增失败！", -1)
			return
		}
	} else {
		// 执行修改
		var LotteryCount int64
		var LotteryCount2 int64
		var lotteryActivity models.MaLotteryActivity
		var lotteryPrizeRecord = []models.MaLotteryPrize{}
		var Info2Map = make(map[string]models.MaLotteryPrize)
		// 1 获取活动数据
		db.Model(&models.MaLotteryActivity{}).Where("id = ? and deleted_at = 0", ID).Take(&lotteryActivity).Count(&LotteryCount)
		if LotteryCount == 0 {
			err = errorx.New("活动不存在", -1)
			return
		}

		// 2.获取奖品数据
		db.Model(&models.MaLotteryPrize{}).Where("id = ? and deleted_at = 0", ID).Find(&lotteryPrizeRecord).Count(&LotteryCount2)
		for _, v := range lotteryPrizeRecord {
			Info2Map[v.ID] = v
		}

		// 微信客服图片如果更改过，需要重新确认
		SystemAdminClient, clientErr := client.GetSystemAdminClient()
		if WechatImg != lotteryActivity.WechatImg {
			if clientErr != nil {
				err = clientErr
				return
			}
			var req system_admin.ConfirmFileReq
			req.FileUrl = WechatImg
			res, err1 := SystemAdminClient.ConfirmFile(context.Background(), &req)
			if err1 != nil && res.Code != 0 {
				logx.Error(context.Background(), "WechatImg edit confirm file error", logx.Any("res", res), logx.Any("err", err1.Error()))
				return
			}
			WechatImg = res.FileUrl
		}

		// 修改主题背景图
		if ThemesImage != "" && ThemesImage != lotteryActivity.ThemesImage {
			if clientErr != nil {
				err = clientErr
				return
			}
			var req1 system_admin.ConfirmFileReq
			req1.FileUrl = ThemesImage
			res1, err2 := SystemAdminClient.ConfirmFile(context.Background(), &req1)
			if err2 != nil && res1.Code != 0 {
				logx.Error(context.Background(), "ThemesImage edit confirm file error", logx.Any("res1", res1), logx.Any("err2", err2.Error()))
				return
			}
			ThemesImage = res1.FileUrl
		}

		// 1.抽奖参与次数规则检查
		if DaliyLotteryTimes > 0 {
			lotteryActivity.DaliyLotteryTimes = DaliyLotteryTimes
		} else {
			DaliyLotteryTimes = -1
		}
		if TotalLotteryTimes > 0 {
			lotteryActivity.TotalLotteryTimes = TotalLotteryTimes
		} else {
			TotalLotteryTimes = -1
		}

		if lotteryActivity.DailyWinTimes > 0 && lotteryActivity.TotalLotteryTimes != 0 &&
			lotteryActivity.DailyWinTimes > lotteryActivity.TotalLotteryTimes {
			err = errorx.New("单日总抽奖机会超过总抽奖机会", -1)
			return
		}

		// 2.兑换日期开始时间不能小于当前活动的开始时间
		if StartTime != 0 {
			lotteryActivity.StartTime = StartTime
		}
		if RedemptionStartTime != 0 {
			lotteryActivity.RedemptionStartTime = RedemptionStartTime
		}
		// if lotteryActivity.RedemptionStartTime < lotteryActivity.StartTime {
		// 	err = errorx.New("兑换时间不能小于当前的活动开始时间", -1)
		// 	return
		// }

		// 执行更新
		UpdateData := make(map[string]interface{})
		UpdateData["name"] = strings.TrimSpace(Name)
		UpdateData["order_amount_required"] = OrderAmountRequired
		UpdateData["order_amount"] = OrderAmount
		UpdateData["start_time"] = StartTime
		UpdateData["end_time"] = EndTime
		if Status == 1 || Status == 2 {
			UpdateData["status"] = Status
		}
		UpdateData["type"] = Type
		UpdateData["desc"] = HandlerGoodsDetail(Desc)
		UpdateData["total_win_times"] = TotalWinTimes
		UpdateData["daily_win_times"] = DailyWinTimes
		UpdateData["total_lottery_times"] = TotalLotteryTimes
		UpdateData["daliy_lottery_times"] = DaliyLotteryTimes
		UpdateData["service_phone"] = ServicePhone
		UpdateData["wechat_img"] = strings.TrimSpace(WechatImg)   // 微信客服图片地址
		UpdateData["allow_citys"] = AllowCitys                    // 允许城市
		UpdateData["redemption_start_time"] = RedemptionStartTime // 固定日期开始时间
		UpdateData["redemption_end_time"] = RedemptionEndTime     // 固定日期结束时间
		UpdateData["redemption_start_week"] = RedemptionStartWeek // 固定时长
		UpdateData["themes_color"] = ThemesColor
		UpdateData["themes_image"] = ThemesImage

		// 允许参与的机器,最多添加500个
		// 删除之前的 obj_type == 1时，obj_id 是奖项ID.  type == 1,2时，obj_id 是活动ID
		dao.ObjAssociation{}.Delete(context.Background(), dal.Q, define.AssociationLotteryRobot, ID, "")
		if AllowRobots != "" {
			// 解析字符串到数组
			records := []*models.MaObjAssociation{}
			var AllowRobotsSlice = strings.Split(AllowRobots, ",")
			for _, v := range AllowRobotsSlice {
				records = append(records, &models.MaObjAssociation{
					AssociationType: int(define.AssociationLotteryRobot),
					ObjID:           ID,
					AssociationID:   v,
				})
			}
			_, err = dao.ObjAssociation{}.Add(context.Background(), dal.Q, records, 300)
			if err != nil {
				err = errorx.New("操作失败", -1)
				return
			}
		}

		// 允许参与的商品,最多添加100个
		// 删除之前的 obj_type == 3时，obj_id 是奖项ID.  type == 1,2时，obj_id 是活动ID
		dao.ObjAssociation{}.Delete(context.Background(), dal.Q, define.AssociationLotteryGoods, ID, "")
		if AllowGoods != "" {
			// 解析字符串到数组
			records := []*models.MaObjAssociation{}
			var allowGoodsIDs = strings.Split(AllowGoods, ",")
			for _, goodsID := range allowGoodsIDs {
				records = append(records, &models.MaObjAssociation{
					AssociationType: int(define.AssociationLotteryGoods),
					ObjID:           ID,
					AssociationID:   goodsID,
				})
			}
			_, err = dao.ObjAssociation{}.Add(context.Background(), dal.Q, records, 300)
			if err != nil {
				err = errorx.New("操作失败", -1)
				return
			}
		}

		// 编辑时，保存奖品图片时，检测和数据库的图片地址是否一致，如果不一致，把上传的图片进行重新确认！
		if len(PrizeData) > 0 {
			// 先删除以前的奖项。
			db.Model(&models.MaLotteryPrizeRule{}).
				Where("lottery_activity_id = ?", ID).
				Delete(&models.MaLotteryPrizeRule{})

			// 1 再重新写入奖品规则表 【规则有：多个或单个】
			for _, v := range PrizeData {
				UUID1, _ := helper.UUID{}.String()
				var prizeRule models.MaLotteryPrizeRule
				prizeRule.ID = UUID1
				prizeRule.Sort = v.Sort
				prizeRule.Name = v.Name
				prizeRule.LotteryActivityID = ID
				prizeRule.LotteryPrizeType = v.LotteryPrizeType
				prizeRule.WinOdds = v.WinOdds
				prizeRule.Total = v.Total
				prizeRule.RuleType = v.RuleType

				// 写入关联表（存储的是奖品ID）
				if v.PrizeGoodsID != "" {
					// 删除之前的 type == 3时，obj_id 是奖项ID.  type == 1,2时，obj_id 是活动ID
					dao.ObjAssociation{}.Delete(context.Background(), dal.Q, define.AssociationLotteryPrize, v.ID, "")
					// 解析字符串到数组
					records := []*models.MaObjAssociation{}
					var prizeGoodsIDs = strings.Split(v.PrizeGoodsID, ",")
					for _, goodsID := range prizeGoodsIDs {
						records = append(records, &models.MaObjAssociation{
							AssociationType: int(define.AssociationLotteryPrize),
							ObjID:           prizeRule.ID,
							AssociationID:   goodsID,
						})
					}
					_, err = dao.ObjAssociation{}.Add(context.Background(), dal.Q, records, 300)
					if err != nil {
						err = errorx.New("操作失败", -1)
						return
					}
				}
				// 写入奖品规则表
				err = db.Model(&models.MaLotteryPrizeRule{}).Create(&prizeRule).Error
				if err != nil {
					err = errorx.New("操作失败", -1)
					return
				}
			}
		}
		// 执行更新活动表
		db.Model(&models.MaLotteryActivity{}).
			Where("id = ?", ID).
			Updates(&UpdateData)
	}

	return
}

func HandlerGoodsDetail(str string) string {

	SystemAdminClient, clientErr := client.GetSystemAdminClient()
	if clientErr != nil {
		return ""
	}
	reader := strings.NewReader(str)
	doc, err := goquery.NewDocumentFromReader(reader)
	if err == nil {
		doc.Find("img").Each(func(i int, s *goquery.Selection) {
			src, _ := s.Attr("src")
			URL, _ := url.Parse(src)
			match, matchErr := regexp.MatchString("^(/file/sale-admin/).*(/temp/).*$", URL.Path)
			if matchErr == nil && match {
				//文件确认
				var req system_admin.ConfirmFileReq
				req.FileUrl = URL.Path
				res, err1 := SystemAdminClient.ConfirmFile(context.Background(), &req)
				if err1 != nil && res.Code != 0 {
					logx.Error(context.Background(), "goods confirm file error", logx.Any("res", res), logx.Any("err", err.Error()))
					return
				}
				ImagePath := URL.Scheme + "://" + URL.Host + res.FileUrl
				s.SetAttr("src", ImagePath) //修改标签的内容
			}
		})
	}
	newGoods, _ := goquery.OuterHtml(doc.Selection)
	returnHtml := strings.TrimSuffix(strings.TrimPrefix(newGoods, "<html><head></head><body>"), "</body></html>")
	return returnHtml
}
